<script setup lang="ts">
import { onMounted, watch } from 'vue'
import DiyOpeningRemarks from '@/views/diy/chat/components/DiyOpeningRemarks.vue'
import DiyTitleStep from '@/views/diy/chat/components/DiyTitleStep.vue'
import UploadFile from '@/views/agent/chat/components/UploadFile.vue'
import DiyCollectForm from '@/views/diy/chat/components/DiyCollectForm.vue'
import CheckBox from '@/views/diy/chat/components/CheckBox.vue'
import DiyStepLoading from '@/views/diy/chat/components/DiyStepLoading.vue'
import { computed, ref } from 'vue'
import {
  DiyContractReviewProcessLoading,
  DiyContractTypes,
  DiyReviewFocus,
  DiyContractAgentConfig,
} from '@/views/diy/chat/components/data'
import applicationApi from '@/api/application'
import { useRoute } from 'vue-router';
import bus from '@/bus'

const route = useRoute();

const formConfig = [
  {
    title: '输入您的立场',
    description: '你所代表的主体名称，与合同内保持一致，如，未来有限责任公司',
    slotName: 'one'
  },
  {
    title: '选择合同类型',
    description: '选定不同合同类型，会对应不同审查重点',
    slotName: 'two'
  },
  {
    title: '设置审查重点',
    description: '编辑设置合同重点，影响代表方的审查倾向',
    slotName: 'three'
  },
]

const props = withDefaults(
  defineProps<{
    appId?: any
    chatId?: string
    applicationDetails: any
  }>(),
  {
  }
)

const routeQuery = ref({
  type: '',
  code: '200',
  message: '',
  name: '',
  url: '',
  file_id: '',
  uploadMode: '',
})
const reviewClassData = ref<any>([])
const contractAgent = ref<any>([])
const step = ref(0)
const stepNum = ref(1)
const formData: any = ref({
  position: '', // 立场
  supplement: '', // 补充说明
})
const uploadLoadding = ref(false)
const resultContent = ref<any>({})
const loading = ref(false)
const isLocal = ref(false)
const isError = ref(false)
const isErrorType = ref(1) // 1.加载超时 点击超时 2.文件过大导致模型上下文超限

const active = computed(() => {
  if (formData.value.position && !formData.value.type && !formData.value.supplement) {
    return 1
  }
  if (formData.value.position && formData.value.type && !formData.value.supplement) {
    return 2
  }
  if (formData.value.position && formData.value.type && formData.value.supplement) {
    return 3
  }
  return 0
})

const hasSubmit = computed(() => {
  const queryParams = routeQuery.value.name &&  routeQuery.value.url && routeQuery.value.file_id;
  return step.value === 1 && formData.value.position && formData.value.type && queryParams && !loading.value
})

/**
 * type 合同类型
 * name 文件名称
 * url  文件路径
 * file_id  文件 id
 * code   状态码
 * message  状态描述
 * uploadMode=local 本地上传
*/
// 监听路径参数中的字段变化
watch(() => route.query, (newVal) => {
  if (newVal && typeof newVal.uploadMode === 'string' && newVal.uploadMode === 'local') {
    isLocal.value = true;
    routeQuery.value.uploadMode = newVal.uploadMode;
    step.value = 0;
    stepNum.value = 1;
    return;
  }
  if (newVal && typeof newVal.code === 'string') {
    routeQuery.value.code = newVal.code;
    if (newVal.code === '200') {
      step.value = 1;
      stepNum.value = 1;
    }
  }
  if (newVal && typeof newVal.type === 'string') {
    routeQuery.value.type = newVal.type;
  }
  if (newVal && typeof newVal.name === 'string') {
    routeQuery.value.name = newVal.name;
  }
  if (newVal && typeof newVal.file_id === 'string') {
    routeQuery.value.file_id = newVal.file_id;
  }
  if (newVal && typeof newVal.url === 'string') {
    routeQuery.value.url = newVal.url;
  }
  if (newVal && typeof newVal.message === 'string') {
    routeQuery.value.message = newVal.message;
  }

  if( newVal.code && (!routeQuery.value.name || !routeQuery.value.url || !routeQuery.value.file_id) ) {
    step.value = 0;
    routeQuery.value.code = '500'
    stepNum.value = 1;
  }
}, {
  deep: true,
  immediate: true
});

const handleToHome = (obj:any) =>{
  if(obj.code !== 200) {
    window.location.href = window.location.href.split('?')[0] + `?code=500`
  } else {
    const { name, url, file_id } = obj
    window.location.href = window.location.href.split('?')[0] + `?name=${name}&url=${url}&file_id=${file_id}&code=200`
  }
}
const uploadDocumentFile = async(appId: any, chatData: any, fileList: any) => {
  const fm = new FormData()
  for (const f of fileList) {
    fm.append('file', f.raw, f.name)
  }
  applicationApi.uploadFile(appId, chatData.data, fm)
    .then((res) => {
      if(res.code === 200) {
        const { name, url, file_id } = res.data[0]
        handleToHome({ name, url, file_id, code: 200 })
      } else {
        throw Error('上传失败')
      }
    })
    .catch((err) => {
      console.log('[ uploadFile err ]', err)
      handleToHome({ code: 500 })
    });
}

const setDocumentList = async(val: any) => {
  // 模拟三方上传
  uploadLoadding.value = true;
  const { appId, apiKey} = DiyContractAgentConfig[2][1];
  // 获取openid
  applicationApi.getChatOtherOpen(appId, apiKey)
    .then(async(res) => {
      console.log(res)
      if(res.code === 200) {
        const chatData = res.data;
        uploadDocumentFile(appId, chatData, val);
      } else {
        throw Error('上传失败')
      }
    }).catch((err) => {
      console.log('[ getChatOtherOpen err ]', err)
      handleToHome({ code: 500 })
    })
}

function handleTimerIdChange(num: any) {
  console.log('[ handleTimerIdChange ]', num)
  stepNum.value = num
}

/**
 * 获取一个递归函数,处理流式数据
 * @param chat    每一条对话记录
 * @param reader  流数据
 * @param stream  是否是流式数据
 */
 const getWrite = (chat: any, reader: any, stream: boolean) => {
  let tempResult = ''
  /**
   *
   * @param done  是否结束
   * @param value 值
   */
  const write_stream = ({ done, value }: { done: boolean; value: any }, content: any) => {
    try {
      if (done) {
        // ChatManagement.close(chat.id)
        console.log(chat.id)
        return
      }
      const decoder = new TextDecoder('utf-8')
      let str = decoder.decode(value, { stream: true })
      // 这里解释一下 start 因为数据流返回流并不是按照后端chunk返回 我们希望得到的chunk是data:{xxx}\n\n 但是它获取到的可能是 data:{ -> xxx}\n\n 总而言之就是 fetch不能保证每个chunk都说以data:开始 \n\n结束
      tempResult += str
      const split = tempResult.match(/data:.*}\n\n/g)
      if (split) {
        str = split.join('')
        tempResult = tempResult.replace(str, '')
      } else {
        return reader.read().then(write_stream)
      }
      // 这里解释一下 end
      if (str && str.startsWith('data:')) {
        if (split) {
          for (const index in split) {
            const chunk = JSON?.parse(split[index].replace('data:', ''))
            chat.chat_id = chunk.chat_id
            chat.record_id = chunk.chat_record_id
            if (!chunk.is_end) {
              // ChatManagement.appendChunk(chat.id, chunk)
              console.log(chat.id, chunk.reasoning_content, content)
              content.str += chunk.reasoning_content
            }
            if (chunk.is_end) {
              // 流处理成功 返回成功回调
              return Promise.resolve()
            }
          }
        }
      }
    } catch (e) {
      return Promise.reject(e)
    }
    return reader.read().then(write_stream)
  }
  /**
   * 处理 json 响应
   * @param param0
   */
  const write_json = ({ done, value }: { done: boolean; value: any }) => {
    if (done) {
      const result_block = JSON.parse(tempResult)
      if (result_block.code === 500) {
        return Promise.reject(result_block.message)
      } else {
        if (result_block.content) {
          // ChatManagement.append(chat.id, result_block.content)
          console.log(chat.id, result_block.content)
        }
      }
      // ChatManagement.close(chat.id)
      return
    }
    if (value) {
      const decoder = new TextDecoder('utf-8')
      tempResult += decoder.decode(value)
    }
    return reader.read().then(write_json)
  }
  return stream ? write_stream : write_json
}


async function submitItem({ appId, apiKey, token }: any) {
  // 获取token
  const appToken = await applicationApi.postAppAuthentication(token)
  // 获取chatId
  const chatData = await applicationApi.getChatOtherOpen(appId, apiKey)
  const document_list = [
    {
      name: routeQuery.value.name,
      url: routeQuery.value.url,
      file_id: routeQuery.value.file_id,
    }
  ]
  const message = `立场名称:${formData.value.position};补充审查重点:${formData.value.supplement};`

  // 发送对话
  applicationApi
    .postChatMessage1(chatData.data, { document_list, stream: true, message: message, apiKey }, appToken.data)
    .then(async(response) => {
      const name = contractAgent.value.filter((el: any) => el.appId === appId)[0].name
      resultContent.value[appId] = { str: '', name }
      const reader = response.body.getReader()
      // while (true) {
      //   const { done, value } = await reader.read();
      //   if (done) break;
      //   console.log(new TextDecoder().decode(value));
      // }
      // 处理流数据
      const write = getWrite(
        {
          id: 0,
          chat_id: '',
          record_id: '',
          content: '',
          is_end: false
        },
        reader,
        response.headers.get('Content-Type') !== 'application/json',
        // resultContent.value[appId]
      )
      return reader.read().then(write)
    })
    .catch((err) => {
      console.log('[ postChatMessageNew err ]', err)
    })
    .finally(() => {
      console.log('[ finally ]')
    });
  // let str
  // try {
  //   str = extractJSON(data.data?.content) // (JSON.parse(data.data?.content.replaceAll(CONTENT_REGEXP, '')))
  // } catch (error) {
  //   str = { content: '--'}
  // }
  // const name = contractAgent.value.filter((el: any) => el.appId === appId)[0].name
  // resultContent.value[appId] = { ...str, name }
}
// async function sellp () {
//   return new Promise((resolve) => {
//     setInterval(() => {
//       if(Object.keys(resultContent.value).length === 2){
//         resolve(true)
//       }
//     }, 100)
//   })
// }
async function onSubmit () {
  try {
    isError.value = false;
    const message = `立场名称:${formData.value.position};补充审查重点:${formData.value.supplement};`
    bus.emit('chat-input', message)
    step.value = 2;
    stepNum.value = 2;
    loading.value = true;
    
    setTimeout(() => {
      stepNum.value = 3;
    }, 3000);

    setTimeout(()=> {
      step.value = 3;
      loading.value = false;
      stepNum.value = 4;
      showChatAiDiy()
      // @ts-ignore
      window?.sendChatHandle()
    },3500)
    
  } catch (e) {
    console.log(e)
  } finally {
    loading.value = false;
  }
}

function handelOnRetry() {
  window.location.reload()
}

function reviewClass(val: number) {
  loading.value = true
  reviewClassData.value = []
  setTimeout(() => {
    reviewClassData.value = DiyReviewFocus[val]
    contractAgent.value = DiyContractAgentConfig[val]
    loading.value = false
  }, 300)
}

function hiddenChatAiDiy() {
  bus.emit('hidden-chat-message')
}

function showChatAiDiy() {
  bus.emit('show-chat-message')
}

onMounted(() => {
  // 对话中
  bus.on('open-chat-message', async(response: any) => { 
    console.log('[ open-chat-message ]', response)
  })
  // 对话失败
  bus.on('open-chat-message-err', (e: any) => { 
    console.log('[ open-chat-message-err]', e)
    step.value = 2;
    stepNum.value = 3;
    isError.value = true;
    isErrorType.value = e === 424 ? 2 : 1
    hiddenChatAiDiy();
  })
  // 对话结束
  bus.on('open-chat-message-end', () => { 
    console.log('[ open-chat-message-end ]')
  })
})

</script>

<template>
  <div class="diy-box">
    <!--- title -->
    <DiyOpeningRemarks 
      :title="props.applicationDetails.name" 
      :description="props.applicationDetails.desc" 
      :avatar="props.applicationDetails.avatar"
      v-if="!isLocal"
    />
    <!---步骤条-->
    <DiyTitleStep 
      :stepNum="stepNum"  
      v-if="!isLocal && stepNum !== 4"
    />
    <!--上传失败、正在上传、上传框-->
    <div class="loading-page" v-if="step === 0">
      <PageEmpty v-if="routeQuery.code !== '200'" type="3"  text1=" " text2="上传失败，请关闭页面后重试 "/>
      <div  v-else-if="routeQuery.uploadMode === 'local' && !uploadLoadding" style="padding: 60px 20px;">
        <UploadFile 
          :app-id="props.appId" 
          :showFileList="false" 
          @update="setDocumentList" 
          :max-files="1" 
          name="合同" 
          tip="支持格式：doc、docx格式文件" 
          accept=".docx,.doc"
        />
      </div>
      <div
        v-else
        v-loading="step === 0"
        element-loading-text="正在上传文件..."
        style="width: 100%; height: 80%; color: #999;"
      ></div>
    </div>
    <!-- 模型审查-准备开始审查 -->
    <DiyCollectForm v-if="step === 1" :data="formConfig" :active="active">
      <template #one>
        <el-input v-model="formData.position" placeholder="请输入你所代表的主体名称" />
      </template>
      <template #two>
        <el-select v-model="formData.type" placeholder="请选择合同类型" @change="reviewClass">
          <el-option v-for="(item, index) in DiyContractTypes" :key="index" :label="item.label" :value="item.value" />
        </el-select>
      </template>
      <template #three>
        <div v-loading="loading" element-loading-text="加载中...">
          <CheckBox :data="reviewClassData"/>
          <el-input v-model="formData.supplement" type="textarea" :rows="4" placeholder="如需补充审查重点，请填写"/>
        </div>
      </template>
    </DiyCollectForm>
    <!--模型审查-点击开始审查后，以及审查结果-->
    <DiyStepLoading 
      @timerIdChange="handleTimerIdChange" 
      @onRetry="handelOnRetry"
      v-if="step === 2" 
      :data="DiyContractReviewProcessLoading" 
      :loading="loading" 
      :resultContent="resultContent" 
      :applicationDetails="props.applicationDetails" 
      :isError="isError"
      :isErrorType="isErrorType"
    />
    <!--开始审查按钮-->
    <div class="ai-start" v-if="step === 1">
      <el-button type="primary" size="small" @click="onSubmit" :disabled="!hasSubmit">开始审查</el-button>
    </div>
    <!--插槽-->
    <slot name="one"></slot>
  </div>
</template>

<style scoped lang="scss">
.loading-page{
  height: calc(100vh - 60px - 112px);
  width: 100%;
  background-color: #fff;
}
.ai-start{
  background-color: #fff;
  padding: 20px 30px;
  display: flex;
  justify-content: end;
}

.diy-box{
  min-height: 100vh;
  background-color: #fff;
  :deep(.el-step__description){
    padding-right: 0;
  }
  :deep(.checkbox-item){
    width: auto;
  }
}

:deep(.empty-box .empty-title){
  bottom: 80px;
}

:deep(.el-loading-text) {
  color: #999;
}

</style>
